/*
 * 演示设置显示驱动程序 - 为站点设置实现显示和编辑逻辑
 * 
 * 主要功能：
 * - 为DemoSettings实现站点设置显示和编辑
 * - 提供权限控制的设置管理
 * - 支持编辑器组的分组显示
 * - 实现站点级别的设置更新
 */

using Lombiq.TrainingDemo.Models;
using Lombiq.TrainingDemo.Permissions;
using Lombiq.TrainingDemo.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using OrchardCore.DisplayManagement.Entities;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Settings;
using System.Threading.Tasks;

namespace Lombiq.TrainingDemo.Drivers;

/// <summary>
/// 演示设置显示驱动程序 - 为站点设置实现显示和编辑逻辑
/// 
/// 主要用途：
/// - 为DemoSettings实现站点设置显示和编辑
 /* - 提供权限控制的设置管理
 * - 支持编辑器组的分组显示
 * - 实现站点级别的设置更新
 * 
 * 使用场景：
 * - 在仪表板上显示和编辑站点设置
 * - 控制设置访问权限
 * - 分组管理不同的设置项
 * - 实现站点级别的配置管理
 * 
 * 设计原因：
 * - 提供安全的站点设置管理
 * - 实现基于权限的访问控制
 * - 支持设置的分组组织
 * - 提供统一的设置编辑界面
 * 
 * 设计模式：
 * - 驱动模式：继承SiteDisplayDriver实现设置逻辑
 * - 权限模式：使用IAuthorizationService进行权限检查
 * - 分组模式：使用编辑器组组织设置
 * - 视图模型模式：使用专门的ViewModel传递数据
/// </summary>
// 现在这个显示驱动程序抽象与您之前见过的不同。在Orchard Core中，您可以将不同的对象连接到主对象，
// 这些对象在存储时将在数据库中连接。站点设置就是这样处理的。
 */
public sealed class DemoSettingsDisplayDriver : SiteDisplayDriver<DemoSettings>
{
    /// <summary>
    /// 编辑器组ID - 用于分组显示设置编辑器
    /// 
    /// 功能说明：
    /// - 由于技术上我们只有一个SiteSettings，我们使用编辑器组来分离编辑器
    /// - 将编辑器组ID存储在公开可访问的常量中是个好主意
    /// - 最好将其存储在Constants文件夹中的静态类中
    /// </summary>
    public const string EditorGroupId = "Demo";

    /// <summary>
    /// 设置组ID - 用于过滤编辑器组
    /// 
    /// 功能说明：
    /// - SiteDisplayDriver的抽象属性，必须被重写
    /// - 用于在后台按组名过滤编辑器
    /// - 无需手动检查
    /// </summary>
    protected override string SettingsGroupId => EditorGroupId;

    private readonly IAuthorizationService _authorizationService;
    private readonly IHttpContextAccessor _hca;

    /// <summary>
    /// 构造函数 - 注入所需的服务依赖
    /// </summary>
    /// <param name="authorizationService">授权服务，用于权限检查</param>
    /// <param name="hca">HTTP上下文访问器，用于获取用户信息</param>
    public DemoSettingsDisplayDriver(IAuthorizationService authorizationService, IHttpContextAccessor hca)
    {
        _authorizationService = authorizationService;
        _hca = hca;
    }

    /// <summary>
    /// 编辑方法 - 在仪表板上显示站点设置编辑器
    /// 
    /// 功能说明：
    /// - 检查用户是否有权限管理演示设置
    /// - 使用Initialize帮助器创建编辑器形状
    /// - 设置显示位置和编辑器组
    /// - 支持同步和异步版本
    /// 
    /// 权限控制：
    /// - 使用IsAuthorizedToManageDemoSettingsAsync检查权限
    /// - 未授权用户无法访问设置编辑器
    /// </summary>
    /// <param name="model">站点模型</param>
    /// <param name="section">演示设置部分</param>
    /// <param name="context">编辑器构建上下文</param>
    /// <returns>编辑结果</returns>
    public override async Task<IDisplayResult> EditAsync(ISite model, DemoSettings section, BuildEditorContext context)
    {
        // 您真正不想做的是让未授权用户更新您站点的站点级设置。因此，
        // 为管理设置或与这些设置相关的功能创建单独的权限并在在这里使用它真的很可取。
        // 我们创建了一个，您可以在Permissions/DemoSettingsPermissions.cs文件中看到。
        if (!await IsAuthorizedToManageDemoSettingsAsync())
        {
            // 如果未授权，则返回null，这意味着不会显示任何内容，否则这些内容将由这个DisplayDriver显示。
            return null;
        }

        // 像往常一样，使用Initialize帮助器和视图模型来创建编辑器。
        return Initialize<DemoSettingsViewModel>(
            $"{nameof(DemoSettings)}_Edit",
            viewModel => viewModel.Message = section.Message)
        .Location("Content:1")
        // OnGroup帮助器将确保形状显示在所需的编辑器组上。
        .OnGroup(EditorGroupId);
    }

    /// <summary>
    /// 更新方法 - 处理站点设置的更新逻辑
    /// 
    /// 功能说明：
    /// - 检查是否为我们的编辑器组
    /// - 验证用户权限
    /// - 更新视图模型和设置模型
    /// - 返回编辑结果
    /// 
    /// 更新流程：
    /// 1. 检查编辑器组ID
    /// 2. 验证用户权限
    /// 3. 更新设置值
    /// 4. 返回编辑结果
    /// </summary>
    /// <param name="model">站点模型</param>
    /// <param name="section">演示设置部分</param>
    /// <param name="context">更新上下文</param>
    /// <returns>更新结果</returns>
    public override async Task<IDisplayResult> UpdateAsync(ISite model, DemoSettings section, UpdateEditorContext context)
    {
        // 由于这个DisplayDriver是为ISite对象设计的，如果站点设置编辑器正在更新，
        // 这个UpdateAsync将被每次调用。为确保这是为我们的编辑器组，在这里检查它。
        if (context.GroupId == EditorGroupId)
        {
            // 在这里也进行授权。
            if (!await IsAuthorizedToManageDemoSettingsAsync())
            {
                return null;
            }

            // 像往常一样更新视图模型和设置模型。
            var viewModel = await context.CreateModelAsync<DemoSettingsViewModel>(Prefix);
            section.Message = viewModel.Message;
        }

        return await EditAsync(model, section, context);
    }

    /// <summary>
    /// 检查是否有权限管理演示设置
    /// 
    /// 功能说明：
    /// - 从HTTP上下文获取用户信息
    /// - 使用授权服务检查权限
    /// - 确保只有授权用户可以管理设置
    /// 
    /// 权限检查：
    /// - 检查用户是否存在
    /// - 验证用户是否具有ManageDemoSettings权限
    /// </summary>
    /// <returns>是否有权限管理演示设置</returns>
    private async Task<bool> IsAuthorizedToManageDemoSettingsAsync()
    {
        // 由于User对象在这里不可访问（就像在Controller中可访问一样），
        // 我们需要从HttpContext获取它。
        var user = _hca.HttpContext?.User;

        return user != null && await _authorizationService.AuthorizeAsync(user, DemoSettingsPermissions.ManageDemoSettings);
    }
}

// 下一站：Navigations/DemoSettingsAdminMenu.cs
